(library (collector)
(export make-collector collect-object! collect-append! collector-get)
(import (chezscheme) (utils))

;; This is a simple tool to collect elements into a list
;;
;; it uses mutation so you should only call collector-get
;; once at the very end and not use the collector after that

;; > (import (collector))
;; > (define a (make-collector))
;; > (collect-object! a 1)
;; > (collect-object! a 2)
;; > (collect-object! a 3)
;; > (collector-get a)
;; (1 2 3)

(define (make-collector) (vector '() #f))

(define (collect-object! c x)
  (let ((l (list x)))
    (cond ((vector-ref c 1)
           => (lambda (tail)
                (set-cdr! tail l)
                (vector-set! c 1 l)))
          (else (vector-set! c 0 l)
                (vector-set! c 1 l)))))

(define (find-tail l)
  (if (null? l)
      (error 'find-tail "no tail" l)
      (if (null? (cdr l))
	  l
	  (find-tail (cdr l)))))

(define (collect-append! c l)
  ;; input list must be ours to mutate
  (if (null? l)
      #t
      (cond ((vector-ref c 1) =>
	     (lambda (tail)
	       (set-cdr! tail l)
	       (vector-set! c 1 (find-tail l))))
	    (else
	     (vector-set! c 0 l)
	     (vector-set! c 1 (find-tail l))))))

(define (collector-get c)
  (vector-ref c 0))

)
